﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using System.Web.Security;
using System.Resources;


namespace Booky.DataStorage
{
    /// <summary>
    /// See GetUsers, GetUserById, AddUser, UpdateUser for Mongo CRUD examples
    /// Database name is test. test is the default database name for mongodb. You can run MongoDB on windows using the default db with a console project using the same usage below.
    /// Sample usage:
    /// BookmarkRepository2 r = new BookmarkRepository2();
    /// r.GetUsers(), 
    /// </summary>
    public class BookmarkRepository2
    {
        private const string DatabaseName = "test";
        private const string BookmarkCollName = "bookmark";
        private const string ListCollName = "list";
        private const string UserCollName = "user";
        private const string TagCollName = "tag";

        private const string BookmarkxTagCollName = "bookmarkxtag";
        private const string BookmarkxListCollName = "bookmarkxlist";
        private const string RelatedTagCollName = "relatedtag";
        private const string ShortUrlCollName = "shorturl";

        private readonly MongoServer mongoServer;
        private readonly MongoDatabase mongoDb;

        public BookmarkRepository2()
        {
            mongoServer = MongoServer.Create();
            mongoDb = mongoServer[DatabaseName];
            InitializeClassMaps();
            //CreateIndexes();
        }

        private void InitializeClassMaps()
        {
            if (!BsonClassMap.IsClassMapRegistered(typeof(User)))
            {
                BsonClassMap.RegisterClassMap<User>();
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(Activation)))
            {
                BsonClassMap.RegisterClassMap<Activation>();                
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(Bookmark)))
            {
                BsonClassMap.RegisterClassMap<Bookmark>();              
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(Tag)))
            {
                BsonClassMap.RegisterClassMap<Tag>();
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(BookmarkTag)))
            {
                BsonClassMap.RegisterClassMap<BookmarkTag>();
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(List)))
            {
                BsonClassMap.RegisterClassMap<List>();
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(BookmarkList)))
            {
                BsonClassMap.RegisterClassMap<BookmarkList>();
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(Report)))
            {
                BsonClassMap.RegisterClassMap<Report>();
            }

            if (!BsonClassMap.IsClassMapRegistered(typeof(BookmarkComment)))
            {
                BsonClassMap.RegisterClassMap<BookmarkComment>();
            }
        }

        public void CreateIndexes()
        { 
            MongoCollection<BsonDocument> list1 = mongoDb.GetCollection<BsonDocument>(UserCollName);
            list1.EnsureIndex(IndexKeys.Ascending(UserFamily.Username), IndexOptions.SetUnique(true));
            list1.EnsureIndex(IndexKeys.Ascending(UserFamily.Email), IndexOptions.SetUnique(false));
        
            MongoCollection<BsonDocument> bookmarks = mongoDb.GetCollection<BsonDocument>(BookmarkCollName);
            bookmarks.EnsureIndex(IndexKeys.Ascending(BookmarkFamily.Url), IndexOptions.SetUnique(false));
            bookmarks.EnsureIndex(IndexKeys.Ascending(BookmarkFamily.User), IndexOptions.SetUnique(false));
            bookmarks.EnsureIndex(IndexKeys.Ascending(BookmarkFamily.IsPrivate), IndexOptions.SetUnique(false));
                
            MongoCollection<BsonDocument> list = mongoDb.GetCollection<BsonDocument>(BookmarkxTagCollName);
            list.EnsureIndex(IndexKeys.Ascending(BookmarkxTagFamily.Bookmark), IndexOptions.SetUnique(false));
            list.EnsureIndex(IndexKeys.Ascending(BookmarkxTagFamily.Tag), IndexOptions.SetUnique(false));

            MongoCollection<BsonDocument> tag = mongoDb.GetCollection<BsonDocument>(TagCollName);
            tag.EnsureIndex(IndexKeys.Ascending(TagFamily.Title), IndexOptions.SetUnique(false));
        }
        
        public List<Tag> GetAllPublicTags()
        {
            return GetPublicTags();//PublicUsername
        }

        public List<Tag> GetPublicTagsPaged(int pageNumber, int numItems, out int totalItems)//string username
        {
            int skip = (pageNumber - 1) * numItems;
            MongoCollection<Tag> tags = mongoDb.GetCollection<Tag>(TagCollName);

            List<Tag> allTagList = tags.FindAllAs<Tag>().ToList();

            MongoCursor<Tag> list = tags.FindAllAs<Tag>().SetSortOrder(SortBy.Ascending(TagFamily.Title));

            totalItems = allTagList.Count;
            list.Skip = skip;
            list.Limit = numItems;

            return list.ToList();
        }

        public List<Tag> GetPublicTags()//string username
        {
            MongoCollection<Tag> tags = mongoDb.GetCollection<Tag>(TagCollName);
            return tags.FindAll().SetSortOrder(SortBy.Ascending(TagFamily.Title)).ToList(); 
        }

        //public bool TagExists(string username, string tag)
        //{
        //    IList<Tag> list = GetTags(username);
        //    return list.ToList().Exists(t => t.Title == tag);
        //}

        public List<Bookmark> GetPublicBookmarksPaged(int pageNumber, int numItems, out int totalItems)
        {
            int skip = (pageNumber - 1) * numItems;
            MongoCollection<BsonDocument> bookmarks = mongoDb.GetCollection<BsonDocument>(BookmarkCollName);
            //Sweet, now we can query.
            var query =
                Query.And(
                Query.EQ(BookmarkFamily.IsOriginal, true),
                Query.EQ(BookmarkFamily.IsPrivate, false));

            //List<Bookmark> list = bookmarks.FindAs<Bookmark>(query).ToList();

            IList<Bookmark> allBookmarkList = bookmarks.FindAs<Bookmark>(query).ToList();

            MongoCursor<Bookmark> list = bookmarks.FindAs<Bookmark>(query).SetSortOrder(SortBy.Descending(BookmarkFamily.CreatedOn));
            totalItems = allBookmarkList.Count;
            list.Skip = skip;
            list.Limit = numItems;

            return list.ToList();
        }       


       

   
       
        //TODO add delete for related tag
        public void DeleteTag(string id)
        {
            MongoCollection<Tag> tags = mongoDb.GetCollection<Tag>(TagCollName);
            var query = Query.EQ(TagFamily.Id, ObjectId.Parse(id));
            tags.Remove(query,SafeMode.True);
        }

        public Bookmark GetBookmarkById(ObjectId id)
        {
            MongoCollection<BsonDocument> bookmarks = mongoDb.GetCollection<BsonDocument>(BookmarkCollName);
            return bookmarks.FindOneByIdAs<Bookmark>(id); 
        }

        public List<User> GetUsers()
        {
            MongoCollection<BsonDocument> users = mongoDb.GetCollection<BsonDocument>(UserCollName);
            return users.FindAllAs<User>().ToList();
        }

        public User GetUserById(ObjectId id)
        {
            MongoCollection<BsonDocument> users = mongoDb.GetCollection<BsonDocument>(UserCollName);
            return users.FindOneByIdAs<User>(id);
        }
        
        public User GetUser(string userName)
        {
            User u = null;
            MongoCollection<BsonDocument> users = mongoDb.GetCollection<BsonDocument>(UserCollName);
            //Sweet, now we can query.
            var query = Query.EQ(UserFamily.Username, userName);
            u = users.FindOneAs<User>(query);
            
            return u;
        }

        public ShortUrl GetShortUrl(string ShortCode)
        {
            ShortUrl s = null;
            MongoCollection<BsonDocument> list = mongoDb.GetCollection<BsonDocument>(ShortUrlCollName);
            //Sweet, now we can query.
            var query = Query.EQ("ShortCode", ShortCode);
            s = list.FindOneAs<ShortUrl>(query);

            return s;
        }

        public ObjectId AddShortUrl(ShortUrl ShortUrl)
        {
            MongoCollection<ShortUrl> list = mongoDb.GetCollection<ShortUrl>(ShortUrlCollName);
            list.Insert(ShortUrl, SafeMode.True);
            return ShortUrl.Id;
        }

        public ShortUrl GetShortUrlById(ObjectId id)
        {
            MongoCollection<BsonDocument> tags = mongoDb.GetCollection<BsonDocument>(ShortUrlCollName);
            return tags.FindOneByIdAs<ShortUrl>(id);
        }

        public bool AddUser(User user)
        {
            MongoCollection<User> users = mongoDb.GetCollection<User>(UserCollName);
            
            //Check if the user exists, return false

            if(GetUser(user.Username) != null)
            {
                return false;
            }

            user.Username.ToLower();
            user.IsActive = true;
            user.DtCreatedOn = DateTime.Now.ToUniversalTime().ToString();

            users.Insert(user, SafeMode.True);                     

            //TODO
            //Add a default starting bookmark for the user
            //AddDefaultNewUserBookmark(user.Name);

            //TODO Insert user add audit event
            //TODO call the API add audit event

            return true;
        }

        public bool UpdateUser(User user)
        {
            MongoCollection<User> users = mongoDb.GetCollection<User>(UserCollName);
            if (string.IsNullOrEmpty(user.DtCreatedOn))
            {
                user.DtCreatedOn = DateTime.Now.ToUniversalTime().ToString();
            }
            users.Save(user, SafeMode.True);
            return true;
        }

        public void DeleteUser(string id)
        {
            MongoCollection<User> users = mongoDb.GetCollection<User>(UserCollName);
            var query = Query.EQ(UserFamily.Id, ObjectId.Parse(id));
            users.Remove(query, SafeMode.True);
        }

     

        public bool IsAccountActive(string username)
        {
            var user = GetUser(username);
            if (!user.IsActive)
            {
                return false;
            }
            return true;
        }

     

      

    
        private static DateTime TimestampToDate(string timestamp)
        {
            return string.IsNullOrEmpty(timestamp)
                     ? DateTime.MinValue
                     : new DateTime(Convert.ToInt64(timestamp), DateTimeKind.Utc);
        }

        private static string DateToTimestamp(DateTime date)
        {
            return date.ToUniversalTime().Ticks.ToString();
        }

       
    }
}
